home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / win / pascal / rattle.exe / RATTLE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1991-12-18  |  19.7 KB  |  587 lines

  1. program Rattle;
  2.  
  3. {
  4.   Program:            RATTLE.PAS
  5.   Version:            1.0
  6.   Creation Date:      October 9, 1991
  7.   Modification Date:  December 18, 1991
  8.   Operating System:   MS-DOS 3.x and Windows 3.0
  9.   Hardware Reguired:  Windows-capable computer system
  10.   Programming System: Turbo Pascal for Windows 1.0
  11.   Author:             Craig Boyd
  12.   Ownership:          Copyright 1991 by Craig Boyd
  13.                       All rights reserved
  14.  
  15.   About This Program
  16.  
  17.   Rattle (as in "Shake Rattle 'n Roll") allocates and deallocates blocks
  18.   of memory in a random fashion, stress-testing other running Windows
  19.   applications by subjecting them to adverse and quickly changing memory
  20.   conditions.  Rattle is functionally equivalent to Shaker, a utility
  21.   shipped with the Microsoft Windows Software Development Kit (SDK).  That
  22.   is, it's as functionally equivalent as I can make it without ever laying
  23.   eyes on Shaker or its source code.  My program is based on descriptions
  24.   of the Shaker algorithm obtained from SDK owners.  Plus it has other
  25.   goodies that are all mine.  See the RATTLE.WRI file for complete usage
  26.   and compilation instructions.  Enjoy.
  27.  
  28.  
  29.   Update History
  30.  
  31.   update    ver   description (author)
  32.   -------   ---   -----------
  33.   9110.09   0.0   Work begun. (CSB)
  34.   9110.11   0.0   Yay, we have a working app! (CSB)
  35.   9110.14   0.0   Added status display to AboutBox. (CSB)
  36.   9110.15   0.0   Fixed checkbox bug. (CSB)
  37.   9110.20   0.0   Added icon animation. (CSB)
  38.   9110.21   0.0   Added spacer memory blocks option. (CSB)
  39.   9110.23   1.0   Added 0 timer option to use Rattle as a memory hog.
  40.                   Added option to save settings in WIN.INI.
  41.                   First release uploaded to CompuServe. (CSB)
  42.   9112.18   1.01  Settings now saved in RATTLE.INI.
  43.                   Fixed bug in TRattleDlg.ReadSettings that caused garbage
  44.                   to be returned for values not found in INI file.
  45.                   Second release uploaded to CompuServe. (CSB)
  46. }
  47.  
  48. {R-,X+}
  49.  
  50. uses
  51.   Strings,
  52.   WinTypes,
  53.   WinProcs,
  54.   WObjects;
  55.  
  56. {$R Rattle}
  57.  
  58. {-- Global Declarations -------------------------------------------------}
  59.  
  60. const
  61.   AppName : pchar = 'Rattle';
  62.   IniName : pchar = 'RATTLE.INI';
  63.  
  64.   id_BlockSize  = 101;                                     { control IDs }
  65.   id_BlockCount = 102;
  66.   id_TimerFreq  = 103;
  67.   id_Sound      = 104;
  68.   id_Minimize   = 105;
  69.   id_Animate    = 106;
  70.   id_Spacers    = 107;
  71.  
  72.   id_ShakeIt      = 201;                                       { buttons }
  73.   id_StopIt       = 202;
  74.   id_Reset        = 203;
  75.   id_SaveSettings = 204;
  76.  
  77.   sc_About = 901;                    { system menu command for About box }
  78.  
  79.   id_Status = 101;                         { static control in About box }
  80.  
  81.   BlockFrac = 4;            { size of spacer block: 4 = 1/4 of BlockSize }
  82.   Tick      = true;
  83.   Tock      = false;
  84.  
  85. type
  86.   TMyApp = object(TApplication)
  87.     procedure InitMainWindow; virtual;
  88.   end;
  89.  
  90.   PBlockCollection = ^TBlockCollection;
  91.   TBlockCollection = object(TCollection)
  92.     procedure FreeItem(Item : pointer); virtual;
  93.   end;
  94.  
  95.   PRattleSettings = ^TRattleSettings;
  96.   TRattleSettings = record
  97.     BlockSize,                          { size of memory blocks in bytes }
  98.     BlockCount,                                   { max number of blocks }
  99.     TimerFreq  : longint;            { seconds between block allocations }
  100.     MakeSound,                            { true to beep when allocating }
  101.     Minimize,                             { true to minimize on start up }
  102.     Animate,                         { true to change icon on timer tick }
  103.     Spacers    : boolean;               { true to allocate spacer blocks }
  104.   end;
  105.  
  106.   PRattleDlg = ^TRattleDlg;
  107.   TRattleDlg = object(TDlgWindow)
  108.     Settings,
  109.     StartSettings  : TRattleSettings;
  110.     EditBlockSize,
  111.     EditBlockCount,
  112.     EditTimerFreq  : PEdit;
  113.     ToggleSound,
  114.     ToggleMinimize,
  115.     ToggleAnimate,
  116.     ToggleSpacers  : PCheckBox;
  117.     Blocks         : PBlockCollection;                   { memory blocks }
  118.     Icon1,
  119.     Icon2          : hIcon;
  120.     IconState,
  121.     Running        : boolean;                 { true if timer is running }
  122.     constructor Init(AParent      : PWindowsObject;
  123.                      AName        : pchar;
  124.                      InitSettings : TRattleSettings);
  125.     destructor Done; virtual;
  126.     procedure SetUpWindow; virtual;
  127.     function GetClassName : pchar; virtual;
  128.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  129.     procedure WMSysCommand(var Msg : TMessage);
  130.       virtual wm_First + wm_SysCommand;
  131.     procedure WMTimer(var Msg : TMessage);
  132.       virtual wm_First + wm_Timer;
  133.     procedure ShakeIt(var Msg : TMessage);        { start allocating RAM }
  134.       virtual id_First + id_ShakeIt;
  135.     procedure StopIt(var Msg : TMessage);    { stop program, release RAM }
  136.       virtual id_First + id_StopIt;
  137.     procedure Reset(var Msg : TMessage);      { restore startup settings }
  138.       virtual id_First + id_Reset;
  139.     procedure SaveSettings(var Msg : TMessage);{save setup in RATTLE.INI }
  140.       virtual id_First + id_SaveSettings;
  141.     procedure ResetParams;                    { restore startup settings }
  142.     function GetSettings : boolean;           { get values from controls }
  143.     procedure ReadSettings;                 { read setup from RATTLE.INI }
  144.     procedure Error(Msg : pchar);
  145.   end;
  146.  
  147.   PAboutDialog = ^TAboutDialog;
  148.   TAboutDialog = object(TDialog)
  149.     BlockSize,
  150.     Blocks    : longint;
  151.     constructor Init(AParent        : PWindowsObject;
  152.                      AName          : pchar;
  153.                      InitBlockSize,
  154.                      InitBlockCount : longint);
  155.     procedure SetupWindow; virtual;
  156.   end;
  157.  
  158.   TNumStr = array[0..6] of char;
  159.  
  160. const
  161.   { Program defaults, if none specified in RATTLE.INI }
  162.   DefSettings : TRattleSettings = (
  163.     BlockSize  : 8192;
  164.     BlockCount : 20;
  165.     TimerFreq  : 5;
  166.     MakeSound  : false;
  167.     Minimize   : true;
  168.     Animate    : true;
  169.     Spacers    : false);
  170.  
  171. {-- Global Procedures ---------------------------------------------------}
  172.  
  173. procedure BoolToStr(B : boolean;
  174.                     S : pchar);
  175. {
  176.   Converts the boolean value B into a string ('1' or '0') and stores
  177.   it in the character array pointed to by S.
  178. }
  179.   begin
  180.     if B then strcopy(S,'1') else strcopy(S,'0');
  181.   end { BoolToStr };
  182.  
  183. {-- TRattleDlg Methods --------------------------------------------------}
  184.  
  185. constructor TRattleDlg.Init;
  186.   begin
  187.     TDlgWindow.Init(AParent,AName);
  188.     StartSettings := InitSettings;
  189.     ReadSettings;
  190.     Blocks := nil;
  191.     Running := false;
  192.     IconState := Tock;
  193.     randomize;
  194.     EditBlockSize := new(PEdit,InitResource(@Self,id_BlockSize,sizeof(TNumStr)));
  195.     EditBlockCount := new(PEdit,InitResource(@Self,id_BlockCount,sizeof(TNumStr)));
  196.     EditTimerFreq := new(PEdit,InitResource(@Self,id_TimerFreq,sizeof(TNumStr)));
  197.     ToggleSound := new(PCheckBox,InitResource(@Self,id_Sound));
  198.     ToggleMinimize := new(PCheckBox,InitResource(@Self,id_Minimize));
  199.     ToggleAnimate := new(PCheckBox,InitResource(@Self,id_Animate));
  200.     ToggleSpacers := new(PCheckBox,InitResource(@Self,id_Spacers));
  201.   end { TRattleDlg.Init };
  202.  
  203. destructor TRattleDlg.Done;
  204.   begin
  205.     if Running then KillTimer(HWindow,1);
  206.     if Blocks <> nil then dispose(Blocks,Done);
  207.     TDlgWindow.Done;
  208.   end { TRattleDlg.Done };
  209.  
  210. procedure TRattleDlg.SetUpWindow;
  211.   var
  212.     SysMenu : hMenu;
  213.   begin
  214.     TDlgWindow.SetUpWindow;
  215.  
  216.     { Add About option to system menu }
  217.     SysMenu := GetSystemMenu(hWindow,false);
  218.     AppendMenu(SysMenu,mf_separator,0,nil);
  219.     AppendMenu(SysMenu,mf_String,sc_About,'&About...');
  220.  
  221.     { Set default parameters }
  222.     ResetParams;
  223.   end { TRattleDlg.SetUpWindow };
  224.  
  225. function TRattleDlg.GetClassName;
  226.   begin
  227.     GetClassName := AppName;
  228.   end { TRattleDlg.GetClassName };
  229.  
  230. procedure TRattleDlg.GetWindowClass;
  231.   begin
  232.     TDlgWindow.GetWindowClass(AWndClass);
  233.     Icon1 := LoadIcon(HInstance,'Rattle1');
  234.     Icon2 := LoadIcon(HInstance,'Rattle2');
  235.     AWndClass.hIcon := Icon1;
  236.   end { TRattleDlg.GetWindowClass };
  237.  
  238. procedure TRattleDlg.WMSysCommand;
  239.   var
  240.     Dlg   : PAboutDialog;
  241.     Count : longint;
  242.   begin
  243.     if Msg.wParam = sc_About then begin
  244.       if Blocks = nil then
  245.         Count := 0
  246.       else
  247.         Count := Blocks^.Count;
  248.       new(Dlg,Init(@Self,'AboutBox',Settings.BlockSize,Count));
  249.       Application^.ExecDialog(Dlg);
  250.     end;
  251.     DefWndProc(Msg);
  252.   end { TRattleDlg.WMSysCommand };
  253.  
  254. procedure TRattleDlg.WMTimer(var Msg : TMessage);
  255. {
  256.   Responds to a wm_Timer message by adding a memory block to the Blocks
  257.   collection.  The collection is not allowed to grow beyond the value set
  258.   by BlockCount.  If the Blocks collection is full, then a memory block
  259.   is chosen at random and deleted.  The collection never has more than
  260.   BlockCount items and never consumes more than BlockCount * BlockSize
  261.   bytes of memory.
  262.  
  263.   We also check the Spacers flag before allocating a block.  If true,
  264.   we temporarily allocate a small block of memory before adding a block
  265.   to our collection, then release the temporary block.  This causes even
  266.   more heap fragmentation.
  267.  
  268.   We also perform a couple of steps to make the program a little more fun
  269.   to use.  Sillier, maybe, but definitely more fun.  First, if the
  270.   MakeSound flag is set, we call MessageBeep.  Second, if our window is
  271.   minimized and the Animate flag is set, we toggle the icon.  These two
  272.   extra steps give you an audible and/or visual cue as to what Rattle is
  273.   up to.
  274.  
  275.   This method is not called if TimerFreq is set to zero.
  276. }
  277.   var
  278.     P,
  279.     Spacer : PHandle;
  280.   begin
  281.     with Settings do begin
  282.       if MakeSound then MessageBeep(0);
  283.       if (Animate) and (IsIconic(HWindow)) then begin
  284.         case IconState of
  285.           Tick : SetClassWord(HWindow,gcw_HIcon,Icon1);
  286.           Tock : SetClassWord(HWindow,gcw_HIcon,Icon2);
  287.         end;
  288.         IconState := not IconState;
  289.         InvalidateRect(HWindow,nil,true);
  290.       end;
  291.  
  292.       if Blocks^.Count = BlockCount then
  293.         Blocks^.AtFree(random(BlockCount))         { free a memory block }
  294.       else
  295.         begin
  296.           if Spacers then begin
  297.             new(Spacer);
  298.             Spacer^ := GlobalAlloc(gmem_Fixed,BlockSize div BlockFrac);
  299.             GlobalLock(Spacer^);
  300.           end;
  301.           new(P);                                         { get a handle }
  302.           P^ := GlobalAlloc(gmem_Fixed,BlockSize);    { grab some memory }
  303.           if P^ <> 0 then begin
  304.             GlobalLock(P^);                                    { lock it }
  305.             Blocks^.Insert(P);                { add handle to collection }
  306.           end;
  307.           if Spacers then begin
  308.             GlobalUnlock(Spacer^);
  309.             GlobalFree(Spacer^);
  310.             dispose(Spacer);
  311.           end;
  312.         end;
  313.     end;
  314.   end { TRattleDlg.WMTimer };
  315.  
  316. procedure TRattleDlg.ShakeIt;
  317.   var
  318.     P : PHandle;
  319.     I : integer;
  320.   begin
  321.     if not GetSettings then exit;                    { read the controls }
  322.     with Settings do begin
  323.       if TimerFreq = 0 then              { create collection and fill it }
  324.         begin
  325.           Blocks := new(PBlockCollection,Init(BlockCount,0));
  326.           for I := 1 to BlockCount do begin
  327.             new(P);                                       { get a handle }
  328.             P^ := GlobalAlloc(gmem_Fixed,BlockSize);  { grab some memory }
  329.             if P^ <> 0 then begin
  330.               GlobalLock(P^);                                  { lock it }
  331.               Blocks^.Insert(P);              { add handle to collection }
  332.             end;
  333.           end;
  334.           if MakeSound then MessageBeep(0);
  335.         end
  336.       else
  337.         begin
  338.           if SetTimer(HWindow,1,TimerFreq * 1000,nil) = 0 then begin
  339.             Error('No free timers');
  340.             exit;
  341.           end;
  342.           Running := true;
  343.           Blocks := new(PBlockCollection,Init(BlockCount,0));
  344.         end;
  345.       { Disable all controls except Quit button, enable Stop It! button }
  346.       EnableWindow(GetItemHandle(id_BlockSize),false);
  347.       EnableWindow(GetItemHandle(id_BlockCount),false);
  348.       EnableWindow(GetItemHandle(id_TimerFreq),false);
  349.       EnableWindow(GetItemHandle(id_Sound),false);
  350.       EnableWindow(GetItemHandle(id_Minimize),false);
  351.       EnableWindow(GetItemHandle(id_Animate),false);
  352.       EnableWindow(GetItemHandle(id_Spacers),false);
  353.       EnableWindow(GetItemHandle(id_ShakeIt),false);
  354.       EnableWindow(GetItemHandle(id_StopIt),true);
  355.       EnableWindow(GetItemHandle(id_Reset),false);
  356.       EnableWindow(GetItemHandle(id_SaveSettings),false);
  357.       SetFocus(GetItemHandle(id_StopIt));
  358.       if Minimize then Show(sw_ShowMinimized);
  359.     end;
  360.   end { TRattleDlg.ShakeIt };
  361.  
  362. procedure TRattleDlg.StopIt;
  363.   begin
  364.     if Running then begin
  365.       KillTimer(HWindow,1);
  366.       Running := false;
  367.     end;
  368.     dispose(Blocks,Done);
  369.     Blocks := nil;
  370.     { Enable all controls, disable Stop It! button }
  371.     EnableWindow(GetItemHandle(id_BlockSize),true);
  372.     EnableWindow(GetItemHandle(id_BlockCount),true);
  373.     EnableWindow(GetItemHandle(id_TimerFreq),true);
  374.     EnableWindow(GetItemHandle(id_Sound),true);
  375.     EnableWindow(GetItemHandle(id_Minimize),true);
  376.     EnableWindow(GetItemHandle(id_Animate),true);
  377.     EnableWindow(GetItemHandle(id_Spacers),true);
  378.     EnableWindow(GetItemHandle(id_ShakeIt),true);
  379.     EnableWindow(GetItemHandle(id_StopIt),false);
  380.     EnableWindow(GetItemHandle(id_Reset),true);
  381.     EnableWindow(GetItemHandle(id_SaveSettings),true);
  382.     SetFocus(GetItemHandle(id_ShakeIt));
  383.   end { TRattleDlg.StopIt };
  384.  
  385. procedure TRattleDlg.Reset;
  386.   begin
  387.     ResetParams;
  388.   end { TRattleDlg.Reset };
  389.  
  390. procedure TRattleDlg.SaveSettings;
  391. {
  392.   Save the current control settings as the new defaults, and store them
  393.   in RATTLE.INI file.  They will be loaded the next time Rattle is
  394.   launched.  The current settings also become the new default settings.
  395. }
  396.   var
  397.     S : TNumStr;
  398.   begin
  399.     if not GetSettings then exit;                    { read the controls }
  400.     StartSettings := Settings;
  401.     with StartSettings do begin
  402.       str(BlockSize,S);
  403.       WritePrivateProfileString(AppName,'BlockSize',S,IniName);
  404.       str(BlockCount,S);
  405.       WritePrivateProfileString(AppName,'BlockCount',S,IniName);
  406.       str(TimerFreq,S);
  407.       WritePrivateProfileString(AppName,'TimerFreq',S,IniName);
  408.       BoolToStr(MakeSound,S);
  409.       WritePrivateProfileString(AppName,'Sound',S,IniName);
  410.       BoolToStr(Minimize,S);
  411.       WritePrivateProfileString(AppName,'Minimize',S,IniName);
  412.       BoolToStr(Animate,S);
  413.       WritePrivateProfileString(AppName,'Animate',S,IniName);
  414.       BoolToStr(Spacers,S);
  415.       WritePrivateProfileString(AppName,'Spacers',S,IniName);
  416.     end;
  417.   end { TRattleDlg.SaveSettings };
  418.  
  419. procedure TRattleDlg.ResetParams;
  420. {
  421.   Restore startup settings and update controls.
  422. }
  423.   var
  424.     S : TNumStr;
  425.   begin
  426.     Settings := StartSettings;
  427.     with Settings do begin
  428.       str(BlockSize,S);
  429.       EditBlockSize^.SetText(S);
  430.       str(BlockCount,S);
  431.       EditBlockCount^.SetText(S);
  432.       str(TimerFreq,S);
  433.       EditTimerFreq^.SetText(S);
  434.       if MakeSound then ToggleSound^.Check else ToggleSound^.Uncheck;
  435.       if Minimize then ToggleMinimize^.Check else ToggleMinimize^.Uncheck;
  436.       if Animate then ToggleAnimate^.Check else ToggleAnimate^.Uncheck;
  437.       if Spacers then ToggleSpacers^.Check else ToggleSpacers^.Uncheck;
  438.     end;
  439.   end { TRattleDlg.ResetParams };
  440.  
  441. function TRattleDlg.GetSettings;
  442. {
  443.   Read values from controls and store them in the Settings record.
  444.   Returns false if any numeric values are out of range.
  445. }
  446.   var
  447.     S : TNumStr;
  448.     L : longint;
  449.     E : integer;
  450.     P : PHandle;
  451.   begin
  452.     GetSettings := false;
  453.     with Settings do begin
  454.       EditBlockSize^.GetText(S,sizeof(S));
  455.       val(S,L,E);
  456.       if (E <> 0) or (L < 1) then begin
  457.         Error('Invalid block size');
  458.         SetFocus(EditBlockSize^.HWindow);
  459.         EditBlockSize^.SetSelection(0,strlen(S));
  460.         exit;
  461.       end;
  462.       BlockSize := L;
  463.       EditBlockCount^.GetText(S,sizeof(S));
  464.       val(S,L,E);
  465.       if (E <> 0) or (L < 1) then begin
  466.         Error('Invalid block count');
  467.         SetFocus(EditBlockCount^.HWindow);
  468.         EditBlockCount^.SetSelection(0,strlen(S));
  469.         exit;
  470.       end;
  471.       BlockCount := L;
  472.       EditTimerFreq^.GetText(S,sizeof(S));
  473.       val(S,L,E);
  474.       if (E <> 0) or (L < 0) then begin
  475.         Error('Invalid timer frequency');
  476.         SetFocus(EditTimerFreq^.HWindow);
  477.         EditTimerFreq^.SetSelection(0,strlen(S));
  478.         exit;
  479.       end;
  480.       TimerFreq := L;
  481.       MakeSound := (ToggleSound^.GetCheck = bf_Checked);
  482.       Minimize := (ToggleMinimize^.GetCheck = bf_Checked);
  483.       Animate := (ToggleAnimate^.GetCheck = bf_Checked);
  484.       Spacers := (ToggleSpacers^.GetCheck = bf_Checked);
  485.     end;
  486.     GetSettings := true;
  487.   end { TRattleDlg.GetSettings };
  488.  
  489. procedure TRattleDlg.ReadSettings;
  490. {
  491.   Loads the default program settings from RATTLE.INI.  If the value in
  492.   RATTLE.INI is invalid, or if RATTLE.INI cannot be found, then the startup
  493.   variables are set to the values originally passed in the Init method.
  494. }
  495.   var
  496.     S,
  497.     Def : TNumStr;
  498.     L   : longint;
  499.     E   : integer;
  500.   procedure GetLongSetting(var DefLong : longint;
  501.                                KeyName : pchar);
  502.     begin
  503.       str(DefLong,Def);
  504.       GetPrivateProfileString(AppName,KeyName,Def,S,sizeof(S),IniName);
  505.       val(S,L,E);
  506.       if E = 0 then DefLong := L;
  507.     end;
  508.   procedure GetBoolSetting(var DefBool : boolean;
  509.                                KeyName : pchar);
  510.     begin
  511.       BoolToStr(DefBool,Def);
  512.       GetPrivateProfileString(AppName,KeyName,Def,S,sizeof(S),IniName);
  513.       val(S,L,E);
  514.       if E = 0 then DefBool := (L <> 0);
  515.     end;
  516.   begin
  517.     with StartSettings do begin
  518.       GetLongSetting(BlockSize,'BlockSize');
  519.       GetLongSetting(BlockCount,'BlockCount');
  520.       GetLongSetting(TimerFreq,'TimerFreq');
  521.       GetBoolSetting(MakeSound,'Sound');
  522.       GetBoolSetting(Minimize,'Minimize');
  523.       GetBoolSetting(Animate,'Animate');
  524.       GetBoolSetting(Spacers,'Spacers');
  525.     end;
  526.   end { TRattleDlg.ReadSettings };
  527.  
  528. procedure TRattleDlg.Error;
  529.   begin
  530.     MessageBeep(0);
  531.     MessageBox(HWindow,Msg,'Error',mb_OK or mb_IconExclamation);
  532.   end { TRattleDlg.Error };
  533.  
  534. {-- TBlockCollection Methods --------------------------------------------}
  535.  
  536. procedure TBlockCollection.FreeItem;
  537.   begin
  538.     if Item <> nil then begin
  539.       GlobalUnlock(PHandle(Item)^);
  540.       GlobalFree(PHandle(Item)^);
  541.       dispose(Item);
  542.     end;
  543.   end { TBlockCollection.FreeItem };
  544.  
  545. {-- TAboutDialog Methods ------------------------------------------------}
  546.  
  547. constructor TAboutDialog.Init;
  548.   begin
  549.     TDialog.Init(AParent,AName);
  550.     Blocks := InitBlockCount;
  551.     BlockSize := InitBlockSize;
  552.   end { TAboutDialog.Init };
  553.  
  554. procedure TAboutDialog.SetupWindow;
  555.   var
  556.     Stat    : array[0..60] of char;
  557.     ArgList : array[0..1] of longint;
  558.   begin
  559.     if Blocks <> 0 then
  560.       begin
  561.         ArgList[0] := Blocks;
  562.         ArgList[1] := BlockSize * Blocks;
  563.         wvsprintf(Stat,'%lu blocks (%lu bytes) have been allocated.',ArgList);
  564.       end
  565.     else
  566.       strcopy(Stat,'No memory blocks allocated.');
  567.     SetWindowText(GetItemHandle(id_Status),Stat);
  568.   end { TAboutDialog.SetupWindow };
  569.  
  570. {-- TMyApp Methods ------------------------------------------------------}
  571.  
  572. procedure TMyApp.InitMainWindow;
  573.   begin
  574.     MainWindow := New(PRattleDlg,Init(nil,AppName,DefSettings));
  575.   end { TMyApp.InitMainWindow };
  576.  
  577. {-- Main Program --------------------------------------------------------}
  578.  
  579. var
  580.   MyApp : TMyApp;
  581.  
  582. begin
  583.   MyApp.Init(AppName);
  584.   MyApp.Run;
  585.   MyApp.Done;
  586. end.
  587.